■ 省電力                                                         

  
  

■ Sleep Mode  スリープイン & ウェイク
 <試作品仕様>
   ・ ボタンスイッチを押したらLEDが点滅して Sleep Mode に入る。
   ・ ボタンスイッチをおしたらウェイクする。



   
  <試作品回路図>(→回路図のPDFファイル
    PIC18F87K90をつかった場合の回路図を以下に示します。

 




<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています

 

    

          

   <プログラム例>
#include <stdio.h>
#include <delays.h>

#pragma config FOSC = XT   
#pragma config XINST = OFF
#pragma config  WDTEN = OFF

int PowerMode;

void int0_RB0(void);
   

void delay_ms (long int cycle) 
{
        unsigned long int i = 0;
       for (i = 0; i < cycle; i++)Delay10TCYx(25);    //  Delay10TCY():40μsec  
}


#pragma code low_vector=0x8    //                      
void low_interrupt (void)
{
        _asm GOTO int0_RB0 _endasm
}
#pragma code
#pragma interruptlow int0_RB0
void int0_RB0()              
{
    int i;

    INTCONbits.INT0IF = 0;

    delay_ms(50);

     if(PORTBbits.RB0 == 0)  //RB0ポートをチェックして0なら
    { 
            for(i = 0; i < 4; i++)    // 4 times Flicker
            {
                LATJbits.LATJ0 = 0;    //LED ON
                delay_ms(500);   //500msec delay
               
                LATJbits.LATJ0 = 1;    //LED OFF
                delay_ms(500);   // 500msec
            }
            delay_ms(5000);
            OSCCON = 0 ;    //OSCCON Resiter
           
            Sleep();       
    }
}



void main (void)
{
        TRISA = 0;
        TRISB = 0;
    TRISBbits.TRISB0 = 1;    //RB0/INT0     input Mode

        TRISC = 0;
        TRISD = 0;
        TRISE = 0;
        TRISF = 0;
        TRISG = 0;
        TRISH = 0;
    TRISJ = 0; 

//空きポートを0vにすると消費電流が低減します。
        LATA = 0;
        LATBbits.LATB1 = 0;
        LATBbits.LATB2 = 0;
        LATBbits.LATB3 = 0;
        LATBbits.LATB4 = 0;
        LATBbits.LATB5 = 0;
        LATBbits.LATB6 = 0;
        LATBbits.LATB7 = 0;
        
        LATC = 0;
        LATD = 0;
        LATE = 0;
        LATF = 0;
        LATG = 0;
        LATGbits.LATG2 = 1;
        LATGbits.LATG3 = 1;     


        LATH = 0;


    INTCON2bits.INTEDG0 = 0;    //INT0  up rising detect
                       
    RCONbits.IPEN = 0;        //interrupt priority NO   
    INTCONbits.INT0IE= 1;    //INT0 Enable
 
    INTCONbits.PEIE =1;        //                                                    
    INTCONbits.GIE = 1;        //


     while (1)
    {
    }

}

 

  <動作結果>

 ・消費電流は 0.0μAでした。 手持ちの電流計(テスター: 秋月電子:METEX P-10)の最少測定限界が 0.1μAであることから 0.1μA以下を確認しました。
  尚、マイクロチップのPIC18F87K90のデータシートには下記の値が記載されています。
    Power-Down Current :  60nA(Type)       at Sleep Mode、 25℃、 Vdd = 3.3v、 Regulator:: disabled、 ENVREG = 0, Tied to Vss, RETEN (CONFIG1L<1>) = 1


 


■ スリープモードのSOSCに対する、ウォッチドックタイマの監視

    通常、スリープモードの場合 WDTなども含め全クロックが停止させます。 したがって WDTをクリアする必要はありません。 但し ほとんどのクロックがクロックが停止してしまいますが、
 スリープ中でも動作させることができるクロックとして、SOSCがあります。 スリープモードでSOSCを使った制御をおこなった場合 WDTがタイムアウトしても リセットがかからずウェークするだけとなり
 通常の場合とWDTの挙動と異なります。 WDTがタイムタイムアウトした場合にPICをリセットするには RCONレジスタのTOフラグ( WDT timeout Flag)をチェックしてリセットします。

<試作品仕様>
 ・タイマ1のクロック源は、通常モードでは外付けOSC1 また スリープモードではSOCSとする。
 ・プログラム起動開始時、 LED(RG2:リセット確認用)を1回点滅させること。
 ・タイムアウト時間4秒のWDTの動作を開始させる。
 ・起動後は、通常モードで LED(RG3)を繰り返し点滅させること。
 ・WDTは点滅サイクルの中でクリアする。  通常モードの場合はLED(RG1)を点灯させること。
 ・ボタンスイッチ(SW1)を押すと、通常モードの場合はタイマ1のクロック源を OSC1からSOCSに切り替え、スリープモードに移行する。LED(RG1)は消灯すること。
 ・スリープモードにおいて ボタンスイッチ(SW1)を押すと、ウェイクすること。
 ・スリープモードにおいては タイマ1の割り込みが1秒毎にかかり これによりウェイクして、WDTをクリアし、またLED(RJ0)を1回点滅させた後、再びスリープすること。
 ・WDTのタイムアウトが発生した場合は リセットが発生すること。


  
  <試作品回路図>(→回路図のPDFファイル
    PIC18F87K90をつかった場合の回路図を以下に示します。



<試作品外観>下記の写真には上記回路図にはない、また本テーマと関係のない部品が多々写っています




          

   <プログラム例>


#include <p18f87K90.h>

#include <stdio.h>
#include <delays.h>
#include <portb.h>

#pragma config FOSC = XT        
#pragma config XINST = OFF
#pragma config  WDTEN = ON 
#pragma config  WDTPS = 1024            //postscalor 1/1024  → 4mse x 1024 = 4096msec //timeout

int Flag_Sleep = 0;     //0: Normal mode   1: Sleep mode        

void int0_RB0(void); 
void Interval(void);    
void total_INT(void);   


void delay_ms(long int cycle)  //msec delay   //OSC1モード
{
        unsigned long int i = 0;
        for (i = 0; i < cycle; i++)Delay10TCYx(20);             
}



#pragma code low_vector=0x08  //割込み
void low_interrupt (void)
{
        _asm goto total_INT _endasm
}
#pragma code
#pragma interruptlow total_INT
void total_INT()
{
        if(INTCONbits.INT0IF == 1)int0_RB0();   //INT0(RB0)外部割込みの場合
        if(PIR1bits.TMR1IF == 1)Interval();     //タイマ1の割り込みの場合
} 
void int0_RB0()                // 外部割込み関数
{

        INTCONbits.INT0IF = 0;              //変化割込みのフラグをリセット
        ClrWdt();       //WDT クリア



        if(PORTBbits.RB0 == 0)  //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合
        { 
                if(Flag_Sleep == 0)     //通常モードの場合
                {
                        Flag_Sleep = 1; //スリープモードへ

                        T1CONbits.TMR1CS1 = 1;  //b7:SOSC 
                        T1CONbits.TMR1CS0 = 0;  //b6:
                        T1CONbits.T1CKPS1 = 0;  //b5: prescalor 1/1  
                        T1CONbits.T1CKPS0 = 0;  //b4: 
                        T1CONbits.SOSCEN = 1;   //b3: SOSC: enable
                //      T1CONbits.T1SYNC = 1;   //b2: Do not synchronize the external clock input
                        T1CONbits.RD16 = 1;             //b1: Read/Write mode: 16bit
                        T1CONbits.TMR1ON = 1;   //b0: Timer1 ON

                        T1CON = 0b10001111;             //SOSC モード //32.768KHz

                        LATGbits.LATG1 = 1;     //LED OFF

                }
                else                    //スリープモードの場合
                {
                        Flag_Sleep = 0; //通常モードへ
                        T1CON = 0b00000011;             //OSC1 モード(FOSC/4) //1MHzモード
                        LATGbits.LATG1 = 0;             //LED ON
                }
        }

} 
        


void Interval()                         
{
        PIR1bits.TMR1IF = 0;    //flag clear
        WriteTimer1(0x7FFE);    //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766) 
                                                        //= 1sec

        if(Flag_Sleep == 1)     //スリープモードの場合
        {
                ClrWdt();               // WDT clear //ClrWdt()がなくともリセットは発生しない
                                                //タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる?
                LATJbits.LATJ0 = 0;     //      LED ON
                delay_ms(100);
        
        LATJbits.LATJ0 = 1;     //LED OFF
        }

}



void main (void)
{
        TRISBbits.TRISB0 = 1;   // INT0 SW

        TRISJ = 0;
        TRISG = 0;


        T1CONbits.TMR1CS1 = 0;  //b7: FOSC/4 :Timer1 clock source is the instruction clock  
        T1CONbits.TMR1CS0 = 0;  //b6:
        T1CONbits.T1CKPS1 = 0;  //b5: prescalor 1/1  
        T1CONbits.T1CKPS0 = 0;  //b4: 
        T1CONbits.SOSCEN = 0;   //b3: SOSC: disable
//      T1CONbits.T1SYNC = 0;   //b2: 
        T1CONbits.RD16 = 1;             //b1: Read/Write mode: 16bit
        T1CONbits.TMR1ON = 1;   //b0: Timer1 ON

        T1CON = 0b00000011;             //OSC1 モード(FOSC/4) //1MHzモード



        Flag_Sleep = 0; //通常モード
        LATGbits.LATG1 = 0;     //モード表示LED ON
        LATGbits.LATG3 = 1;

        LATGbits.LATG2 = 1;
        delay_ms(200);  


        LATGbits.LATG2 = 0;     //LED ON  リセット確認用
        delay_ms(200);

        LATGbits.LATG2 = 1;
        delay_ms(200);  

        INTCON2bits.INTEDG0 = 0;        //INT0外部割込み: 立下りエッジ

        WDTCONbits.SWDTEN = 1;  //WDT on

//割り込み許可                             
        RCONbits.IPEN = 0;              //割り込み優先順位なし            
        PIE1bits.TMR1IE = 1;    // Timer innterrupt enable
        INTCONbits.INT0IE= 1;   //INT0外部割込みの許可
        INTCONbits.PEIE =1;                                                                                          
        INTCONbits.GIE = 1;     


        while (1)
        {

                if(Flag_Sleep == 0)     // 通常モード
                {
                        LATGbits.LATG3 = 0;     //LED ON
                        delay_ms(500);
                        LATGbits.LATG3 = 1;     //LED OFF
                        delay_ms(500);
                        ClrWdt();       // WDT clear
                        
                                                
                }
                else    //Sleep モードの場合
                {
                        Sleep();
                        if(RCONbits.TO == 0)Reset();    //      TO: WDT timeout Flag
                }

        
        }



}

<動作結果>

・通常モードでLEDが点滅している時の RG3ポートの電圧波形です。
・スリープモードで SOSCをクロック源とするタイマ1の割り込みで
 ウェイクしてLEDが点滅している時の RJ0ポートの電圧波形です。



<追記> 実際にWDTをスリープモードで使用した場合の消費電流について検討してみました。
 上記構成に対して下記の変更を実施してスリープ電流を観測しました。
  @ ウェイク確認用LEDを非動作とする。
  A 空きポートは出力モードとし、0vを出力する
 

          

   <プログラム例>


#include <p18f87K90.h>

#include <stdio.h>
#include <delays.h>
#include <portb.h>

#pragma config FOSC = XT        
#pragma config XINST = OFF
#pragma config  WDTEN = ON 
#pragma config  WDTPS = 1024            //postscalor 1/1024  → 4mse x 1024 = 4096msec //timeout

int Flag_Sleep = 0;     //0: Normal mode   1: Sleep mode        

void int0_RB0(void); 
void Interval(void);    
void total_INT(void);   


void delay_ms(long int cycle)  //msec delay   //OSC1モード
{
        unsigned long int i = 0;
        for (i = 0; i < cycle; i++)Delay10TCYx(20);             
}



#pragma code low_vector=0x08  //割込み
void low_interrupt (void)
{
        _asm goto total_INT _endasm
}
#pragma code
#pragma interruptlow total_INT
void total_INT()
{
        if(INTCONbits.INT0IF == 1)int0_RB0();   //INT0(RB0)外部割込みの場合
        if(PIR1bits.TMR1IF == 1)Interval();     //タイマ1の割り込みの場合
} 
void int0_RB0()                // 外部割込み関数
{

        INTCONbits.INT0IF = 0;              //変化割込みのフラグをリセット
        ClrWdt();       //WDT クリア



        if(PORTBbits.RB0 == 0)  //RB0ポートをチェックして0なら//ボタンスイッチSW1が押された場合
        { 
                if(Flag_Sleep == 0)     //通常モードの場合
                {
                        Flag_Sleep = 1; //スリープモードへ

                        T1CONbits.TMR1CS1 = 1;  //b7:SOSC 
                        T1CONbits.TMR1CS0 = 0;  //b6:
                        T1CONbits.T1CKPS1 = 0;  //b5: prescalor 1/1  
                        T1CONbits.T1CKPS0 = 0;  //b4: 
                        T1CONbits.SOSCEN = 1;   //b3: SOSC: enable
                //      T1CONbits.T1SYNC = 1;   //b2: Do not synchronize the external clock input
                        T1CONbits.RD16 = 1;             //b1: Read/Write mode: 16bit
                        T1CONbits.TMR1ON = 1;   //b0: Timer1 ON

                        T1CON = 0b10001111;             //SOSC モード //32.768KHz

                        LATGbits.LATG1 = 1;     //LED OFF

                }
                else                    //スリープモードの場合
                {
                        Flag_Sleep = 0; //通常モードへ
                        T1CON = 0b00000011;             //OSC1 モード(FOSC/4) //1MHzモード
                        LATGbits.LATG1 = 0;             //LED ON
                }
        }

} 
        


void Interval()                         
{
        PIR1bits.TMR1IF = 0;    //flag clear
        WriteTimer1(0x7FFE);    //31μsec x (0xFFFF - 0x7FFE) = 31 x (65536-32766) 
                                                        //= 1sec

        if(Flag_Sleep == 1)     //スリープモードの場合
        {
                ClrWdt();               // WDT clear //ClrWdt()がなくともリセットは発生しない
                                                //タイマ割りこみがないとリセットは発生する。 ウェイクでWDTがクリアされる?
//              LATJbits.LATJ0 = 0;     //      LED ON
//              delay_ms(100);
//              LATJbits.LATJ0 = 1;     //LED OFF
        }

}



void main (void)
{
        TRISBbits.TRISB0 = 1;   // INT0 SW

        TRISJ = 0;
        TRISG = 0;


        TRISA = 0;
        TRISB = 0;
    TRISBbits.TRISB0 = 1;    //RB0/INT0     input Mode

        TRISC = 0;
        TRISD = 0;
        TRISE = 0;
        TRISF = 0;
        TRISG = 0;
        TRISH = 0;
    TRISJ = 0; 


        LATA = 0;
        LATBbits.LATB1 = 0;
        LATBbits.LATB2 = 0;
        LATBbits.LATB3 = 0;
        LATBbits.LATB4 = 0;
        LATBbits.LATB5 = 0;
        LATBbits.LATB6 = 0;
        LATBbits.LATB7 = 0;
        
        LATC = 0;
        LATD = 0;
        LATE = 0;
        LATF = 0;
        LATG = 0;
        LATGbits.LATG1 = 1;
        LATGbits.LATG2 = 1;
        LATGbits.LATG3 = 1;     


        LATH = 0;
        LATJ = 0;
        LATJbits.LATJ0 = 1;


        T1CONbits.TMR1CS1 = 0;  //b7: FOSC/4 :Timer1 clock source is the instruction clock  
        T1CONbits.TMR1CS0 = 0;  //b6:
        T1CONbits.T1CKPS1 = 0;  //b5: prescalor 1/1  
        T1CONbits.T1CKPS0 = 0;  //b4: 
        T1CONbits.SOSCEN = 0;   //b3: SOSC: disable
//      T1CONbits.T1SYNC = 0;   //b2: 
        T1CONbits.RD16 = 1;             //b1: Read/Write mode: 16bit
        T1CONbits.TMR1ON = 1;   //b0: Timer1 ON

        T1CON = 0b00000011;             //OSC1 モード(FOSC/4) //1MHzモード



        Flag_Sleep = 0; //通常モード
        LATGbits.LATG1 = 0;     //モード表示LED ON
        LATGbits.LATG3 = 1;

        LATGbits.LATG2 = 1;
        delay_ms(200);  


        LATGbits.LATG2 = 0;     //LED ON  リセット確認用
        delay_ms(200);

        LATGbits.LATG2 = 1;
        delay_ms(200);  

        INTCON2bits.INTEDG0 = 0;        //INT0外部割込み: 立下りエッジ

        WDTCONbits.SWDTEN = 1;  //WDT on

//割り込み許可                             
        RCONbits.IPEN = 0;              //割り込み優先順位なし            
        PIE1bits.TMR1IE = 1;    // Timer innterrupt enable
        INTCONbits.INT0IE= 1;   //INT0外部割込みの許可
        INTCONbits.PEIE =1;                                                                                          
        INTCONbits.GIE = 1;     


        while (1)
        {

                if(Flag_Sleep == 0)     // 通常モード
                {
                        LATGbits.LATG3 = 0;     //LED ON
                        delay_ms(500);
                        LATGbits.LATG3 = 1;     //LED OFF
                        delay_ms(500);
                        ClrWdt();       // WDT clear
                        
                                                
                }
                else    //Sleep モードの場合
                {
                        Sleep();
                        if(RCONbits.TO == 0)Reset();    //      TO: WDT timeout Flag
                }

        
        }



}


  

<追記の実験結果>
  ・ Sleep中の電流は1.9μA程度である。ウェイクした時の電流(波高値)は(推定)20μA以下である。